GitHub Dependabotが自動作成してくれるPRの中で、パッチバージョンの更新だけAutoMergeする
吉川@広島です。
先日、
GitHubにDependabotを導入して依存ライブラリを自動アップデートする | DevelopersIO
という記事を書きました。さらに掲題のことを実現するにはどうすれば良いのかなーと思っていたところ、ちょうどはてなブックマークで下のドキュメントが浮上していて解決できましたので、その方法を紹介したいと思います。
[B! github] Automating Dependabot with GitHub Actions - GitHub Docs
Automating Dependabot with GitHub Actions - GitHub Docs
TL;DR
- GitHub DependabotでPRを自動作成する
- GitHub ActionsでPRを自動マージする
という方法で実現できました。
Dependabot設定ファイル
# .github/dependabot.yml version: 2 updates: - package-ecosystem: 'npm' directory: '/' schedule: interval: 'daily'
GitHub Actions設定ファイル
# .github/workflows/dependabot-auto-merge.yml name: Dependabot auto-merge on: pull_request_target permissions: pull-requests: write contents: write jobs: dependabot: runs-on: ubuntu-latest if: ${{ github.actor == 'dependabot[bot]' }} steps: - name: Dependabot metadata id: metadata uses: dependabot/[email protected] with: github-token: '${{ secrets.GITHUB_TOKEN }}' - name: Enable auto-merge for Dependabot PRs if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-patch' }} run: gh pr merge --auto --merge "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
やってみた
依存パッケージがいい感じに古くなっているサンプルとして、「何か思いついて作りかけたけど飽きて途中で放置している個人リポジトリ」を対象に試してみました(皆さんもあると思います・・・)。
マイナーバージョン以上の更新はPR自動作成に留まっています。
パッチバージョンの更新はPR作成+自動マージしてくれています。
詳細を開くと、このようにGitHub Actionsによってマージされたことが確認できました。
なぜパッチバージョンだけ自動マージしたいのか
多くのパッケージがsemverに沿ったバージョニングを行っています。
セマンティック バージョニング 2.0.0 | Semantic Versioning
1.APIの変更に互換性のない場合はメジャーバージョンを、
2.後方互換性があり機能性を追加した場合はマイナーバージョンを、
3.後方互換性を伴うバグ修正をした場合はパッチバージョンを上げます。
{メジャー}.{マイナー}.{パッチ}
ということですね。
で、Dependabotが自動で作成してくれるアップデートPRをどのように管理していくかですが、品質面での理想を追求するならば、
- すべてのアップデートについて、開発者が確認した上で手動マージする
というフローを採ることになりそうです。
ただ、そのプロジェクトの性質や依存パッケージの数、開発者のリソースにもよりますが、あまり完璧主義な方針を採ってしまうと、「すべてのチェックにかかる工数が大きくなりすぎて、プロジェクトの他の作業の進行にしわ寄せがいってしまって辛い」となる可能性もあり、その結果継続的なアップデートの取り組みが放置されてしまう、といったケースもそれなりにあるようです。
そこで、
- プロジェクトにとって無理がない
- 一定以上安全といえる
を両立できる落とし所を模索する必要があり、その一つとして
- メジャーバージョン・マイナーバージョンのアップデートについては開発者が確認した上で手動マージする
- パッチバージョンのアップデートは自動マージする
という方針がそれなりによく採られているのではないかと思います。
GitHub Actionsで何をやっているのか
自分なりに調べた結果、おそらくこういうことだろうと理解できた範囲で共有していきます。
github.actor
if: ${{ github.actor == 'dependabot[bot]' }}
Context and expression syntax for GitHub Actions - GitHub Docs
The login of the user that initiated the workflow run.
- workflowを起動させたユーザがDependabotかどうか
を判定するための条件と考えておけば良さそうです。
dependabot/fetch-metadata
uses: dependabot/[email protected]
Extract information about the dependencies being updated by a Dependabot-generated PR.
- Dependabotが作成したPRから依存関係の情報を抽出する
という役割を果たしているようです。
具体的には、 steps.metadata.outputs
というグローバルオブジェクト(と呼べば良いのか・・・?)に情報をセットしてくれるので、後述する「パッチバージョンのアップデートかどうか」といった条件分岐のためにこの情報を取り出して利用するということになります。
どうやってそんなことしてるんだろう・・・と気になったのでコードを確認したところ、 @actions/core
パッケージの setOutput
という関数を利用していました。
fetch-metadata/output.ts at main · dependabot/fetch-metadata
steps.metadata.outputs.update-type
if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-patch' }}
dependabot/fetch-metadataでセットした情報を取得して、
- パッチバージョンのアップデートかどうか
を判定しています。
GITHUB_TOKEN
github-token: '${{ secrets.GITHUB_TOKEN }}'
GitHub Secretsに自分で何かセットする必要があるのかな?と思いますが、それはしなくて良いようです。
GitHubは、ワークフローで利用するGITHUB_TOKENシークレットを自動的に生成します。 このGITHUB_TOKENは、ワークフローの実行内での認証に利用できます。
このように自動生成されるトークンを取得して利用しているので、ただ上の記述をするだけで良く、その他に自分で何かセットしたりすることは必要ありません。
さらに色々やりたい
さらにフローをカスタムしたいという場合も、GitHub Actions上という性質を活かしていくらでも応用ができそうです。
例えば、
- name: Enable auto-merge for Dependabot PRs if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-patch' }} run: | + npm run test # jestによる自動テストを走らせる gh pr merge --auto --merge "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
のようにすることで「自動テストがPASSした場合のみマージする」みたいなことも実現できると思います。